import subprocess
import time
import signal
import logging
from typing import Optional

from tools.constant.redis_keys import CAMERA_LIVE
from tools.utils.logging_setting import set_logging
from tools.utils.redis_client import redis_client_instance

set_logging()


class RTSPToRTMP:
    def __init__(self, rtmp_url: str):
        self.process = None
        self.current_rtsp_url = None
        self.rtmp_url = rtmp_url
        self.redis_client = redis_client_instance()

        # 配置日志
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s'
        )
        self.logger = logging.getLogger(__name__)

    def start_ffmpeg(self, rtsp_url: str) -> bool:
        """
        启动 FFmpeg 进程
        """
        try:
            command = [
                'ffmpeg',
                '-re',  # 以实时速度读取输入
                '-rtsp_transport', 'tcp',  # 使用 TCP 传输
                '-i', rtsp_url,  # 输入的 RTSP URL
                '-c:v', 'copy',  # 视频流直接复制，不重新编码
                '-c:a', 'aac',   # 音频转换为 aac
                '-f', 'flv',     # 输出格式为 FLV
                self.rtmp_url    # 使用实例变量中的 RTMP 输出 URL
            ]

            print("Starting FFmpeg...")
            self.process = subprocess.Popen(
                command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )
            print("FFmpeg started.")

            self.current_rtsp_url = rtsp_url
            self.logger.info(f"FFmpeg started: {rtsp_url} -> {self.rtmp_url}")

            # 捕获输出
            # stdout, stderr = self.process.communicate()
            # print("FFmpeg stdout:", stdout.decode())  # 打印标准输出
            # print("FFmpeg stderr:", stderr.decode())   # 打印错误输出

            return True

        except Exception as e:
            self.logger.error(f"Failed to start FFmpeg: {str(e)}")
            return False

    def stop_ffmpeg(self) -> None:
        """
        停止 FFmpeg 进程
        """
        if self.process:
            try:
                self.process.terminate()
                try:
                    self.process.wait(timeout=5)  # 等待进程终止
                except subprocess.TimeoutExpired:
                    self.process.kill()  # 如果等待超时，强制结束进程

                self.logger.info("FFmpeg stopped")
            except Exception as e:
                self.logger.error(f"Error stopping FFmpeg: {str(e)}")

            self.process = None
            self.current_rtsp_url = None

    def restart_stream(self, rtsp_url: str) -> bool:
        """
        重启流
        """
        self.logger.info("Restarting stream...")
        self.stop_ffmpeg()
        time.sleep(1)  # 等待进程完全终止
        # rtsp_url = converter.redis_client.get(CAMERA_LIVE).decode("utf-8")
        return self.start_ffmpeg(rtsp_url)

    def check_process_health(self) -> bool:
        """
        检查 FFmpeg 进程是否健康
        """
        if not self.process:
            return False

        if self.process.poll() is None:
            return True
        else:
            # 进程已终止，打印错误信息
            returncode = self.process.returncode
            logging.error(
                f"FFmpeg process terminated with return code: {returncode}")
            return False

    def monitor_stream(self, check_interval: int = 5) -> None:
        """
        监控流的状态，如果异常则重启
        """
        last_rtsp_url = None
        while True:
            try:
                rtsp_url = self.redis_client.get(CAMERA_LIVE).decode("utf-8")
                rtsp_url = rtsp_url.replace("\"", "")
                if rtsp_url != last_rtsp_url:
                    last_rtsp_url = rtsp_url
                    self.logger.info(f"RTSP URL changed: {rtsp_url}")
                    self.restart_stream(rtsp_url)

                if not self.check_process_health():
                    self.logger.warning(
                        "Stream is down, attempting to restart...")
                    self.restart_stream(rtsp_url)

                time.sleep(check_interval)

            except KeyboardInterrupt:
                self.logger.info("Received interrupt signal, stopping...")
                self.stop_ffmpeg()
                break
            except (subprocess.CalledProcessError, ValueError) as e:
                self.logger.error(f"Error in monitor_stream: {str(e)}")
                time.sleep(check_interval)
                self.restart_stream(rtsp_url)
            except Exception as e:
                self.logger.error(
                    f"Unexpected error in monitor_stream: {str(e)}")
                time.sleep(check_interval)
                self.restart_stream(rtsp_url)


def main(rtpmp_url):
    # 使用示例
    rtmp_url = "rtmp://172.16.80.97:1935/live/stream3"
    converter = RTSPToRTMP(rtmp_url)

    try:
        # 启动转换
        rtsp_url = converter.redis_client.get(CAMERA_LIVE).decode("utf-8")
        if converter.start_ffmpeg(rtsp_url.replace("\"", "")):
            # 开始监控
            logging.info("开始播放")
            converter.monitor_stream(check_interval=15)
    except KeyboardInterrupt:
        converter.stop_ffmpeg()
    finally:
        converter.stop_ffmpeg()


if __name__ == "__main__":
    main("rtmp://172.16.80.117:1935/live/stream3")
